package com.boboPlanet.user.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.boboPlanet.comm.constance.BaseDictConfigEnum;
import com.boboPlanet.comm.constance.DataSource;
import com.boboPlanet.comm.context.BusinessStartTimeContext;
import com.boboPlanet.comm.context.LoginUserContext;
import com.boboPlanet.comm.entity.po.LoginUserInfoPO;
import com.boboPlanet.comm.exception.BusinessException;
import com.boboPlanet.comm.utils.AutoGenerateIds;
import com.boboPlanet.comm.utils.DateUtil;
import com.boboPlanet.user.entity.dto.MenuDTO;
import com.boboPlanet.user.entity.po.MenuPO;
import com.boboPlanet.user.entity.po.RoleMenuPO;
import com.boboPlanet.user.entity.po.RolePO;
import com.boboPlanet.user.entity.po.UserRolePO;
import com.boboPlanet.user.entity.vo.CurrentUserInfoVO;
import com.boboPlanet.user.entity.vo.MenuVO;
import com.boboPlanet.user.entity.vo.RoleMenuDTO;
import com.boboPlanet.user.entity.vo.UserRoleVO;
import com.boboPlanet.user.mapper.MenuMapper;
import com.boboPlanet.user.mapper.UserInfoConvert;
import com.boboPlanet.user.mapper.UserOperationMapper;
import com.boboPlanet.user.service.MenuService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: TODO
 * @Author: mis_wu
 * @Date: 2023/2/21
 **/
@Service
@Slf4j
public class MenuServiceImpl implements MenuService {

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private UserOperationMapper userOperationMapper;


    @DS(DataSource.MENU)
    public List<MenuVO> getAllMenus() {
        List<MenuPO> menus = menuMapper.getAllMenus(BaseDictConfigEnum.bobo_planet.name());
        return this.getMenus(menus);
    }

    @Override
    @DS(DataSource.MENU)
    public List<MenuVO> getNotLoginMenus() {
        List<MenuPO> menusPo = menuMapper.getNotLoginMenus(BaseDictConfigEnum.bobo_planet.name(), 0);

        return this.getMenus(menusPo);
    }

    @Override
    @DS(DataSource.MENU)
    public List<MenuVO> getLoginMenus() {
        LoginUserInfoPO userInfo = LoginUserContext.getLoginUserInfoPO();
        List<UserRolePO> userRoles = menuMapper.getRoleInfoByUserId(userInfo.getUserId());
        if (userRoles == null || userRoles.size() == 0){
            throw BusinessException.build("当前用户无角色信息,请联系管理员!!!");
        }
        Long roleId;
        if (userRoles.size() == 1){
            roleId = userRoles.get(0).getRoleId();
        }else {
            //todo 若有多个角色让用户选择登录
            roleId = userRoles.stream().filter(o -> o.getRoleLevel() != null).max(Comparator.comparing(UserRolePO::getRoleLevel)).get().getRoleId();
        }
        List<Long> menuIds = menuMapper.getMenusByRoleId(roleId,BaseDictConfigEnum.bobo_planet.name());
        if (menuIds == null || menuIds.size() == 0){
            return Collections.emptyList();
        }
        List<MenuPO> menusPo = menuMapper.selectMenuBatchIds(menuIds);
        if (menusPo == null || menusPo.size() == 0){
            return Collections.emptyList();
        }
        return this.getMenus(menusPo);

    }

    /**
     * 组装菜单信息
     * @param menusPo List
     * @return List
     */
    private List<MenuVO> getMenus(List<MenuPO> menusPo){
        List<MenuVO> parentMenus = new ArrayList<>();
        MenuVO vo;
        for (MenuPO po : menusPo) {
            if (po.getParentMenuId() == null){
                //父级菜单
                vo = new MenuVO();
                vo.setMenuId(po.getMenuId());
                vo.setMenuName(po.getMenuName());
                vo.setMenuIcon(po.getMenuIcon());
                vo.setMenuType(po.getMenuType());
                vo.setMenuSort(po.getMenuSort());
                vo.setMenuSystem(po.getMenuSystem());
                parentMenus.add(vo);
            }
        }
        if (parentMenus.isEmpty()){
            return Collections.emptyList();
        }
        //将子菜单分组
        Map<Long,List<MenuPO>> menus = menusPo.stream().filter(o -> o.getParentMenuId() != null).collect(Collectors.groupingBy(MenuPO::getParentMenuId));
        for (MenuVO parentMenu : parentMenus) {
            if (menus.isEmpty()){
                continue;
            }
            List<MenuPO> childMenus = menus.get(parentMenu.getMenuId());
            List<MenuVO> menuVOS = UserInfoConvert.INSTANCE.pos2vos(childMenus);
            parentMenu.setChildMenus(menuVOS);
        }

        return parentMenus;
    }

    @DS(DataSource.MENU)
    public Boolean addMenu(MenuDTO dto) {
        if (dto == null){
            throw BusinessException.build("添加菜单失败,参数异常！！！");
        }
        if (StringUtils.isBlank(dto.getMenuName())){
            throw BusinessException.build("添加菜单失败,菜单名称不能为空！！！");
        }
        if (StringUtils.isBlank(dto.getMenuCode())){
            throw BusinessException.build("添加菜单失败,菜单编码不能为空！！！");
        }
        if (StringUtils.isBlank(dto.getMenuIcon())){
            throw BusinessException.build("添加菜单失败,菜单图标不能为空！！！");
        }
        boolean exist = menuMapper.judgeMenuIsExist(dto.getMenuName(),dto.getMenuCode(),BaseDictConfigEnum.bobo_planet.name()) > 0;
        if (exist){
            throw BusinessException.build("菜单名称、菜单编码已经存在,请重新添加！！！");
        }

        MenuPO po = new MenuPO();
        po.setMenuId(AutoGenerateIds.getGenerateId());
        po.setMenuName(dto.getMenuName());
        po.setMenuCode(dto.getMenuCode());
        po.setMenuIcon(dto.getMenuIcon());
        po.setSkipPath(dto.getSkipPath());
        po.setMenuType(dto.getMenuType());
        po.setFlagInvalid(dto.getInvalidFlag() == null ? 1:dto.getInvalidFlag());
        po.setMenuSort(dto.getMenuSort());
        po.setParentMenuId(dto.getParentMenuId());
        po.setMenuSystem(dto.getMenuSys());
        po.setMenuState(dto.getMenuState());
        po.setUpdateTime(BusinessStartTimeContext.getTime());
        po.setUpdateUser(LoginUserContext.getLoginUserInfoPO().getUserName());

        return menuMapper.insert(po) > 0;
    }

    @Override
    @DS(DataSource.MENU)
    public List<MenuVO> findParentMenus() {
        return menuMapper.getParentMenus(null,BaseDictConfigEnum.bobo_planet.name());
    }

    /**
     * @param role RoleName
     * @param isAll true:获取所有(角色管理)  false:获取正常(分配菜单时)
     * @return RolePO
     */
    @DS(DataSource.MENU)
    public List<RolePO> getRoleList(String role,boolean isAll) {
        return menuMapper.getRoleList(role,BaseDictConfigEnum.bobo_planet.name(),false,isAll);
    }

    @Override
    @DS(DataSource.MENU)
    public Boolean addRole(String role) {
        RolePO po = new RolePO();
        List<RolePO> roleList = menuMapper.getRoleList(role, BaseDictConfigEnum.bobo_planet.name(),true,false);
        if (!roleList.isEmpty()){
            throw BusinessException.build("该角色已经存在,请重新添加!!!");
        }
        po.setRoleId(AutoGenerateIds.getGenerateId());
        po.setRoleName(role);
        po.setFlagInvalid(0);
        po.setRoleNo(1);
        po.setSysName(BaseDictConfigEnum.bobo_planet.name());
        po.setPlanetCreateTime(DateUtil.getNowDate());
        po.setPlanetCreateUser(LoginUserContext.getLoginUserInfoPO().getUserName());

        return menuMapper.saveRole(po) > 0;
    }

    @Override
    @DS(DataSource.MENU)
    public Boolean delRole(Long roleId) {
        return menuMapper.delRole(roleId) > 0;
    }

    @Override
    @DS(DataSource.MENU)
    public Boolean showRole(Long roleId) {
        return menuMapper.showRole(roleId) > 0;
    }

    @Override
    public List<CurrentUserInfoVO> getSysUserInfo(String content) {
        return userOperationMapper.getSysUserInfo(content);
    }

    @Override
    @DS(DataSource.MENU)
    public List<UserRoleVO> getRolesByUserId(Long userId) {
        return menuMapper.getRolesByUserId(userId,BaseDictConfigEnum.bobo_planet.name());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @DS(DataSource.MENU)
    public Boolean setRoleForUser(Long userId,  String[] roleIds) {

        if (roleIds == null || roleIds.length == 0){
            throw BusinessException.build("请选择有效的角色信息,不可为空!!!");
        }

        List<String> collect = Arrays.stream(roleIds).collect(Collectors.toList());
        List<Long> existRoles = new ArrayList<>();
        for (Iterator<String> roles = collect.iterator();roles.hasNext();){
            String role = roles.next();
            Long roleId = Long.valueOf(role);
            boolean exist = menuMapper.judgeUserRoleIsExist(userId, roleId) > 0;
            if (exist) {
                existRoles.add(roleId);
                roles.remove();
            }
        }
        //勾选并且已存在角色除外，其他的角色删除
        menuMapper.deleteRoleByUserId(userId,existRoles);
        if (!collect.isEmpty()){
            collect.forEach( roleId -> {
                boolean save = menuMapper.distributionRole(AutoGenerateIds.getGenerateId(), userId, Long.valueOf(roleId)) > 0;
                if (!save) {
                    throw BusinessException.build("分配角色失败,请联系管理员!!!");
                }
            });
        }
        return true;
    }



    @Override
    @DS(DataSource.MENU)
    public RoleMenuDTO getMenuInfoByRoleId(Long roleId) {
        if (roleId == null){
            throw BusinessException.build("角色信息错误,参数不能为空!!!");
        }
        List<Long> menuIds = menuMapper.getMenusByRoleId(roleId,BaseDictConfigEnum.bobo_planet.name());
        if (menuIds == null || menuIds.isEmpty()){
            return new RoleMenuDTO(Collections.emptyList(),Collections.emptyList());
        }
        //过滤出子菜单,只返回子菜单，前端有了子菜单会自动勾选父菜单
        List<Long> childIds = menuMapper.selectChildMenusByMenuIds(menuIds,BaseDictConfigEnum.bobo_planet.name());

        List<MenuPO> menusPo = menuMapper.selectMenuBatchIds(menuIds);
        if (menusPo == null || menusPo.size() == 0){
            return new RoleMenuDTO(Collections.emptyList(),Collections.emptyList());
        }
        List<MenuVO> menus = this.getMenus(menusPo);

        return new RoleMenuDTO(menus,childIds);
    }


    @DS(DataSource.MENU)
    @Transactional(rollbackFor = Exception.class)
    public Boolean distributeMenuForRole(Long roleId, List<Long> menuIds) {
        if (roleId == null || menuIds == null || menuIds.size() == 0){
            throw BusinessException.build("分配菜单失败,角色和菜单参数错误!!!");
        }

        //todo: 查出该角色所有菜单 看选中的是否存在，存在的不管，不存在的删除，新增的插入
        List<Long> roleMenuIds = menuMapper.getMenusByRoleId(roleId,BaseDictConfigEnum.bobo_planet.name());

        if (!roleMenuIds.isEmpty()){
            List<Long> delMenu = new ArrayList<>();
            for (Long menuId : roleMenuIds) {
                if (!menuIds.contains(menuId)){
                    delMenu.add(menuId);
                }else {
                    //包含说明已存在不用管移除即可，剩余的则是新增的
                    menuIds.remove(menuId);
                }
            }
            //todo: delMenu中是子菜单还是父菜单，子菜单直接删除，父菜单的话也要删除其对应子菜单
            for (Long menu : delMenu) {
                List<MenuVO> parentMenus = menuMapper.getParentMenus(menu, BaseDictConfigEnum.bobo_planet.name());
                if (parentMenus != null && parentMenus.size() > 0){
                    //根据父菜单查询子菜单id
                    List<Long> childIds = menuMapper.selectChildMenuIds(menu,BaseDictConfigEnum.bobo_planet.name());
                    //删除角色的子菜单信息
                    if (childIds != null && childIds.size() > 0){
                        menuMapper.deleteRoleMenu(roleId,childIds);
                    }
                }
            }
            if(!delMenu.isEmpty()){
                menuMapper.deleteRoleMenu(roleId,delMenu);
            }
        }
        List<RoleMenuPO> rmList = new ArrayList<>(menuIds.size());
        for (Long menuId : menuIds) {
            RoleMenuPO roleMenuPO = new RoleMenuPO();
            roleMenuPO.setRoleMenuId(AutoGenerateIds.getGenerateId());
            roleMenuPO.setRoleId(roleId);
            roleMenuPO.setMenuId(menuId);
            roleMenuPO.setSysName(BaseDictConfigEnum.bobo_planet.name());
            rmList.add(roleMenuPO);
        }
        for (RoleMenuPO roleMenuPO : rmList) {
            menuMapper.insertRoleMenu(roleMenuPO);
        }

//        menuMapper.batchInsert(rmList);

        return true;
    }

}
